/******************************************************************************
 *                                                                          
 * Copyright (c) 2008 Nuvoton Technology. All rights reserved.             
 *                                                                
 * FILENAME
 *     AC97.c
 *
 * VERSION
 *     1.0 
 *
 * DESCRIPTION
 *
 *
 *
 *
 * DATA STRUCTURES
 *     None
 *
 * FUNCTIONS
 *
 *
 *     
 * HISTORY
 *      2007.09.27              Created by Shih-Jen Lu
 *
 *
 * REMARK
 *     None
 *
 *
 **************************************************************************/

#ifdef ECOS
#include "stdio.h"
#include "stdlib.h"
#include "kapi.h"
#include "diag.h"
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wblib.h"
#endif

#include "wbio.h"

#include "NUC900_Audio_Regs.h"
#include "NUC900_Audio.h"
#include "AC97.h"

#ifdef HAVE_AC97



static BOOL	volatile _bPlayDmaToggle, _bRecDmaToggle;

extern BOOL g_fInUse[];


static void Delay(int nCnt)
{
	 int volatile loop;
	for (loop=0; loop<nCnt; loop++);
}


static UINT16  ac97_read_register(INT nIdx)
{
	 INT volatile	nWait;
	 int status =1;
	
	/* set the R_WB bit and write register index */
	writew(REG_ACTL_ACOS1, 0x80 | nIdx);
	
	/* set the valid frame bit and valid slots */
	writew(REG_ACTL_ACOS0, inpw(REG_ACTL_ACOS0) | 0x11);

	Delay(0x100);
	
	/* polling the AC_R_FINISH */
	for (nWait = 0; nWait < 0x10000; nWait++)
	{
		if (readw(REG_ACTL_ACCON) & AC_R_FINISH)
			break;
	}
	if (nWait == 0x10000)
	{
		_error_msg("ac97_read_register time out!\n");
		status = 0;
		//_debug_msg("REG_ACTL_ACOS0=%x,  REG_ACTL_ACOS1=%x,  REG_ACTL_ACIS0=%x,  REG_ACTL_ACIS1=%x\n", readw(REG_ACTL_ACOS0), readw(REG_ACTL_ACOS1), readw(REG_ACTL_ACIS0), readw(REG_ACTL_ACIS1));
	}

	writew(REG_ACTL_ACOS0,  inpw(REG_ACTL_ACOS0) &~0x1);
		
	//if (readw(REG_ACTL_ACIS0) & 0x0C != 0x0C)
	//	_debug_msg("ac97_read_register - valid slot was not set, 0x%x\n", readw(REG_ACTL_ACIS0));
		
	if ((readw(REG_ACTL_ACIS1) >> 2) != nIdx)
	{	_debug_msg("ac97_read_register - R_INDEX of REG_ACTL_ACIS1 not match!, 0x%x\n. %d", readw(REG_ACTL_ACIS1), status);	}

	Delay(100);
	return (readw(REG_ACTL_ACIS2) & 0xFFFF);
}


static INT  ac97_write_register(INT nIdx, UINT16 sValue)
{
	INT volatile	nWait;
	INT status = 1;
	//_debug_smg("ac97_write_register - index = 0x%x, value = 0x%x\n", nIdx, sValue);

	/* clear the R_WB bit and write register index */
	writew(REG_ACTL_ACOS1, nIdx);
	
	/* write register value */
	writew(REG_ACTL_ACOS2, sValue);
	
	/* set the valid frame bit and valid slots */
	writew(REG_ACTL_ACOS0, inpw(REG_ACTL_ACOS0) | 0x13);
	
	Delay(0x1000);

	/* polling the AC_W_FINISH */
	for (nWait = 0; nWait < 0x10000; nWait++)
	{
		if (!(readw(REG_ACTL_ACCON) & AC_W_FINISH))
			break;
	}
	if (nWait==0x10000)
	{
		status = 0;
		_debug_msg("write register timeout\n");
	}
	writew(REG_ACTL_ACOS0, inpw(REG_ACTL_ACOS0) &~0x3);

	//if (readw(REG_ACTL_ACIS0) & 0x08 != 0x08)
	//	_debug_msg("                   ! valid slot was not set, 0x%x\n", readw(REG_ACTL_ACIS0));
		
	if (ac97_read_register(nIdx) != sValue)
	{	
		_debug_msg("ac97_write_register, nIdx=0x%x, mismatch, 0x%x must be 0x%x\n. %d", nIdx, ac97_read_register(nIdx), sValue,status); 
	}
	
	return 0;
}


#if 0
static void ac97_read_all_registers()
{
	_debug_msg("AC97_RESET            = 0x%04x\r\n", ac97_read_register(AC97_RESET));
	_debug_msg("AC97_MASTER_VOLUME    = 0x%04x\r\n", ac97_read_register(AC97_MASTER_VOLUME));
	_debug_msg("AC97_AUX_OUT_VOLUME   = 0x%04x\r\n", ac97_read_register(AC97_AUX_OUT_VOLUME));
	_debug_msg("AC97_MONO_VOLUME      = 0x%04x\r\n", ac97_read_register(AC97_MONO_VOLUME));
	_debug_msg("AC97_MASTER_TONE      = 0x%04x\r\n", ac97_read_register(AC97_MASTER_TONE));
	_debug_msg("AC97_PC_BEEP_VOLUME   = 0x%04x\r\n", ac97_read_register(AC97_PC_BEEP_VOLUME));
	_debug_msg("AC97_PHONE_VOLUME     = 0x%04x\r\n", ac97_read_register(AC97_PHONE_VOLUME));
	_debug_msg("AC97_MIC_VOLUME       = 0x%04x\r\n", ac97_read_register(AC97_MIC_VOLUME));
	_debug_msg("AC97_LINE_IN_VOLUME   = 0x%04x\n", ac97_read_register(AC97_LINE_IN_VOLUME));
	_debug_msg("AC97_CD_VOLUME        = 0x%04x\n", ac97_read_register(AC97_CD_VOLUME));
	_debug_msg("AC97_VIDEO_VOLUME     = 0x%04x\n", ac97_read_register(AC97_VIDEO_VOLUME));
	_debug_msg("AC97_AUX_IN_VOLUME    = 0x%04x\n", ac97_read_register(AC97_AUX_IN_VOLUME));
	_debug_msg("AC97_PCM_OUT_VOLUME   = 0x%04x\n", ac97_read_register(AC97_PCM_OUT_VOLUME));
	_debug_msg("AC97_RECORD_SELECT    = 0x%04x\n", ac97_read_register(AC97_RECORD_SELECT));
	_debug_msg("AC97_RECORD_GAIN      = 0x%04x\n", ac97_read_register(AC97_RECORD_GAIN));
	_debug_msg("AC97_RECORD_GAIN_MIC  = 0x%04x\n", ac97_read_register(AC97_RECORD_GAIN_MIC));
	_debug_msg("AC97_GENERAL_PURPOSE  = 0x%04x\n", ac97_read_register(AC97_GENERAL_PURPOSE));
	_debug_msg("AC97_3D_CONTROL       = 0x%04x\n", ac97_read_register(AC97_3D_CONTROL));
	_debug_msg("AC97_AUDIO_INT_PAGING = 0x%04x\n", ac97_read_register(AC97_AUDIO_INT_PAGING));
	_debug_msg("AC97_POWERDOWN_CTRL   = 0x%04x\n", ac97_read_register(AC97_POWERDOWN_CTRL));
	_debug_msg("AC97_FRONT_DAC_RATE   = 0x%04x\n", ac97_read_register(AC97_FRONT_DAC_RATE));
}
#endif


#ifdef ECOS
cyg_uint32  ac97_isr(cyg_vector_t vector, cyg_addrword_t data)
#else
static void  ac97_isr()
#endif
{
	UINT32 nINTStatus;
	nINTStatus = inpw(REG_ACTL_CON);


	if (nINTStatus & T_DMA_IRQ)
	{
		writew(REG_ACTL_CON, readw(REG_ACTL_CON) | T_DMA_IRQ);
		
		if ((readw(REG_ACTL_PSR) & P_DMA_MIDDLE_IRQ) && (readw(REG_ACTL_PSR)&P_DMA_END_IRQ))
    	{
    		_debug_msg("psr=0x%x\n",inpw(REG_ACTL_PSR));
    		writew(REG_ACTL_PSR, P_DMA_MIDDLE_IRQ | P_DMA_END_IRQ);
    		_debug_msg("both mid and end isr  psr=0x%x\n",inpw(REG_ACTL_PSR));
#ifdef ECOS
			cyg_interrupt_acknowledge(IRQ_ACTL);
			return CYG_ISR_HANDLED;
#else
            return;
#endif
    	}
    	
		if (_bPlayDmaToggle == 0)
		{
			if (readw(REG_ACTL_PSR) & P_DMA_MIDDLE_IRQ)
				writew(REG_ACTL_PSR, P_DMA_MIDDLE_IRQ);
			else
				_error_msg("ac97_play_isr - miss middle!\n");
			_bPlayDmaToggle = 1;
    	
			g_fnWAVOutCallBack((UINT8 *)_uAuPlayBuffUncachedAddr, 
											_uAuPlayBuffSize/2);
		}
		else
		{
			if (readw(REG_ACTL_PSR) & P_DMA_END_IRQ)
				writew(REG_ACTL_PSR, P_DMA_END_IRQ);
			else
			    _error_msg("ac97_play_isr - miss end!\n");	
			
			_bPlayDmaToggle = 0;
    	
			g_fnWAVOutCallBack((UINT8 *)(_uAuPlayBuffUncachedAddr + _uAuPlayBuffSize / 2), 
										_uAuPlayBuffSize/2);
		}
	}
	
	if (nINTStatus & R_DMA_IRQ)
	{
		writew(REG_ACTL_CON, readw(REG_ACTL_CON) | R_DMA_IRQ);
		if ((readw(REG_ACTL_RSR) & R_DMA_MIDDLE_IRQ) && (readw(REG_ACTL_RSR)&R_DMA_END_IRQ))
    	{
    		_debug_msg("psr=0x%x\n",inpw(REG_ACTL_RSR));
    		writew(REG_ACTL_RSR, R_DMA_MIDDLE_IRQ | R_DMA_END_IRQ);
    		_debug_msg("both mid and end isr  psr=0x%x\n",inpw(REG_ACTL_RSR));
#ifdef ECOS
			cyg_interrupt_acknowledge(IRQ_ACTL);
			return CYG_ISR_HANDLED;
#else
            return;
#endif
    	}
    	

		if (_bRecDmaToggle == 0)
		{
			if (readw(REG_ACTL_RSR) & R_DMA_MIDDLE_IRQ)
				writew(REG_ACTL_RSR, R_DMA_MIDDLE_IRQ);
			else
				{ _error_msg("ac97_rec_isr - miss middle!\n");	}
			_bRecDmaToggle = 1;
    	
			g_fnWAVInCallBack((UINT8 *)_uAuRecBuffUncachedAddr, _uAuRecBuffSize/2);
		}
		else
		{
			if (readw(REG_ACTL_RSR) & R_DMA_END_IRQ)
				writew(REG_ACTL_RSR, R_DMA_END_IRQ);
			else
				{ _error_msg("ac97_rec_isr - miss end!\n");	}
			_bRecDmaToggle = 0;
    	
			g_fnWAVInCallBack((UINT8 *)(_uAuRecBuffUncachedAddr + _uAuRecBuffSize / 2), 
										_uAuRecBuffSize/2);
		}
		
	}

#ifdef ECOS
			cyg_interrupt_acknowledge(IRQ_ACTL);
			return CYG_ISR_HANDLED;
#endif
	
}		



static BOOL ColdResetAC97()
{
    UINT32 ntimeout=0x1000;
    
    /* cold reset AC 97 */
    writew(REG_ACTL_ACCON, readw(REG_ACTL_ACCON) | AC_C_RES);
    Delay(1000);
    writew(REG_ACTL_ACCON, readw(REG_ACTL_ACCON) & ~AC_C_RES);
    Delay(1000);
    while(ntimeout--)
    {
    	if ((readw(REG_ACTL_ACIS0) & 0x10))
    		break;
    }
    if (ntimeout==0)
    {
        _debug_msg("Error - AC97 codec ready was not set, cold reset failed!\n");
        return FALSE;
    }
    
    return TRUE;
}
static BOOL InitACLink()
{
    
    BOOL bRetVal;
    outpw(REG_MFSEL,inpw(REG_MFSEL)&~(3<<22) | (2<<22) );
    /* enable audio controller and AC-link interface */
    writew(REG_ACTL_CON, I2S_AC_PIN_SEL | AUDIO_EN | ACLINK_EN | T_DMA_IRQ | R_DMA_IRQ);
    Delay(1000);
    /* reset Audio Controller */
    writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) | ACTL_RESET_BIT);
    Delay(1000);
    writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) & ~ACTL_RESET_BIT);
    Delay(1000);
    /* reset AC-link interface */
    writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) | AC_RESET);
    Delay(1000);
    writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) & ~AC_RESET);
    Delay(1000);
    
    
    
    bRetVal = ColdResetAC97();
    return bRetVal;
}
static BOOL AC97SetSampleRate(UINT16 SampleRate,WAPI_INOUT apidir)
{
	BOOL bRetVal=FALSE;

    switch(SampleRate)
    {
        case 8000:
        case 11025:
        case 16000:
        case 22050:
        case 32000:
        case 44100:
            ac97_write_register(AC97_EXT_AUDIO_CTRL, ac97_read_register(AC97_EXT_AUDIO_CTRL)|0x1);//enable variable rate
	    case 48000:
            bRetVal=TRUE;
            break;
        default:
            bRetVal=FALSE;
            return (bRetVal);
	}
	/* set play sampling rate */
	if (apidir == WAPI_OUT)
	{
		ac97_write_register(AC97_FRONT_DAC_RATE,SampleRate & 0xffff);
	}else
	{
		ac97_write_register(AC97_LR_ADC_RATE,SampleRate & 0xffff);
	}
	
	return (bRetVal);
	
}
/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      AC97_SetVolume                                                   */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Set AC97 left and right channel play volume.                     */
/*                                                                       */
/* INPUTS                                                                */
/*      uVolume    play volume of left & right channel                   */
/*                 16 bits of right (0xRRRRLLLL)                         */
/*                  0:  mute                                             */
/*             0xffff: maxmum volume                                     */
/*                                                                       */
/*                                                                       */
/* OUTPUTS                                                               */
/*      None                                                             */
/*                                                                       */
/* RETURN                                                                */
/*      0           Success                                              */
/*		Otherwise	error												 */
/*                                                                       */
/*************************************************************************/
static BOOL AC97_SetVolume(UINT32 uVolume)
{
    UINT16 ucAC97VolL;
    UINT16 ucAC97VolR;
    UINT16 ucAC97VolBoth;
    UINT16 ucAC97VolCur;

    // Volume is 16 bits of Left and 16 bits of right (0xRRRRLLLL)

    ucAC97VolR=0x3e - (UINT16) ((uVolume & 0x0000FFFF) >> 10); // six bits of volume
    
    ucAC97VolL=0x3e - (UINT16) (((uVolume & 0xFFFF0000)>>16) >> 10);  //six bits of volume
    

    ucAC97VolBoth=(ucAC97VolL<<8) | ucAC97VolR;

    ucAC97VolCur=ac97_read_register( AC97_AUX_OUT_VOLUME);

    ucAC97VolCur &= 0xC0C0;  //only keep the upper 2 bits of each byte
    ucAC97VolBoth &= ~0xC0C0;  //only keep lower 6 bits of each byte
    ucAC97VolBoth |= ucAC97VolCur;  //add current volume bites


    return (ac97_write_register(AC97_AUX_OUT_VOLUME, ucAC97VolBoth));
    //return TRUE;

}
BOOL
AudioOutMute(
   BOOL mute
   )
{
    UINT16 Ac97Data=0;

    Ac97Data = ac97_read_register(AC97_AUX_OUT_VOLUME);  //read the current hardware volume

    if( mute )
    {
        Ac97Data=Ac97Data |   0x8000;    //set the mute bit
    }
    else
        Ac97Data=Ac97Data & ~ 0x8000;    //clear the mute bit


    return( ac97_write_register(AC97_AUX_OUT_VOLUME, Ac97Data) );
}
BOOL
AudioInMute(
   BOOL mute
   )
{
    UINT16 Ac97Data=0;

    Ac97Data=ac97_read_register(AC97_RECORD_GAIN);           //read the current hardware volume

    if( mute )
    {
        Ac97Data=Ac97Data |   0x8000;    //set the mute bit
    }
    else
        Ac97Data=Ac97Data &  ~ 0x8000;   //clear the mute bit


    return( ac97_write_register(AC97_RECORD_GAIN, Ac97Data) );
}

static BOOL AC97PowerOn(WAPI_INOUT apidir ,PWAVEFORMATEX pFormat)
{
    
	
	if (AC97SetSampleRate(pFormat->nSamplesPerSec,apidir)==FALSE)
	{
		_debug_msg("Error - sample rate %d not support!!\n",pFormat->nSamplesPerSec);
		return FALSE; 
	}
	
	if (apidir==WAPI_OUT)
	{
	    ac97_write_register(AC97_GENERAL_PURPOSE, 0);//select MIC1 in, loopback disable
	    ac97_write_register(AC97_MONO_VOLUME, 0x000f);
		ac97_write_register(AC97_PCM_OUT_VOLUME, 0x0808);//AC97 set the PCM out value
		ac97_write_register(AC97_MASTER_VOLUME, 0x0808);
		//AC97_SetVolume(v_nVolume);
	}
	else
	{
	    ac97_write_register(AC97_GENERAL_PURPOSE, 0);//select MIC1 in, loopback disable
	    ac97_write_register(AC97_RECORD_SELECT, 0);	/* record select MIC in */
		//ac97_write_register(AC97_RECORD_SELECT, 0x4);	// record select LINE in
		ac97_write_register(AC97_RECORD_GAIN, 0x0f0f);//Set the record gain value
		ac97_write_register(AC97_RECORD_GAIN_MIC, 0x0000);//0db
		ac97_write_register(AC97_MIC_VOLUME, 0x0000);//+12db
	    ac97_write_register(AC97_LINE_IN_VOLUME, 0x0808);//0db
	}
	
	
	
	return TRUE;
	
}

INT  Initialize_AC97(WAPI_INOUT apidir ,PWAVEFORMATEX pFormat)
{
    static FirstTime = TRUE;
    if (FirstTime)
    {
        if (InitACLink()==FALSE)
            return ERR_AU_INITDEV_FAIL;
        FirstTime = FALSE;
    }    
    if (AC97PowerOn(apidir , pFormat)==FALSE)//TODO: if error occur, must power off
        return ERR_AU_INITDEV_FAIL;
    
    if (apidir==WAPI_OUT)
    {
        if (pFormat->fnWAVCallBack==NULL)
        {
            _debug_msg("Without callback function\n");
            return ERR_AU_INITDEV_FAIL;
        }   
        g_fnWAVOutCallBack = pFormat->fnWAVCallBack;

    }
    else
    {
        if (pFormat->fnWAVCallBack==NULL)
        {
            _debug_msg("Without callback function\n");
            return ERR_AU_INITDEV_FAIL;
        }
        g_fnWAVInCallBack = pFormat->fnWAVCallBack;    
    }
    
    // Initialize audio[AC97] ISR
#ifdef ECOS
    //sysSetInterruptType(IRQ_ACTL, HIGH_LEVEL_SENSITIVE);
    cyg_interrupt_create(IRQ_ACTL, 1, 0, ac97_isr, NULL, 
					&pFormat->int_handle_audio, &pFormat->int_holder_audio);
    cyg_interrupt_attach(pFormat->int_handle_audio);
    cyg_interrupt_unmask(IRQ_ACTL);
#else
    sysSetInterruptType(IRQ_ACTL, HIGH_LEVEL_SENSITIVE);
    sysInstallISR(IRQ_LEVEL_1, IRQ_ACTL, (PVOID)ac97_isr);
    sysEnableInterrupt(IRQ_ACTL);
#endif
    
    
	return 0;	
}


BOOL WaveProc_AC97(
    WAPI_INOUT apidir,
    UINT32      nCode,
    UINT32      nParam1,
    UINT32      nParam2
    )
{
    switch(nCode)
    {
        case WPDM_START:
            if (nParam1==NULL)
                return FALSE;
            if (apidir==WAPI_OUT)
            {
                ac97StartPlay((PWAVEFORMATEX) nParam1);
            }else
            {
                ac97StartRecord((PWAVEFORMATEX) nParam1);
            }
            break;
        case WPDM_STOP:
            if (apidir==WAPI_OUT)
            {
                ac97StopPlay();
            }else
            {
                ac97StopRecord();
            }
            break;
        case WPDM_SETPLAYVOLUME:
            v_nVolume = nParam1;
            AC97_SetVolume(*((PUINT32) nParam1));
            break;
        case WPDM_GETVOLUME:
            *((PUINT32) nParam1) = v_nVolume;
            break;
        default:
            return FALSE;
    }
    return TRUE;
}






/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      ac97StartPlay                                                   */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Start AC97 playback.                                             */
/*                                                                       */
/* INPUTS                                                                */
/*      fnCallBack     client program provided callback function. The audio */
/*                  driver will call back to get next block of PCM data  */
/*      nSamplingRate  the playback sampling rate. Supported sampling    */
/*                  rate are 48000, 44100, 32000, 24000, 22050, 16000,   */
/*                  11025, and 8000 Hz                                   */
/*      nChannels	number of playback nChannels                          */
/*					1: single channel, otherwise: double nChannels        */
/*                                                                       */
/* OUTPUTS                                                               */
/*      None                                                             */
/*                                                                       */
/* RETURN                                                                */
/*      0           Success                                              */
/*		Otherwise	error												 */
/*                                                                       */
/*************************************************************************/
static INT  ac97StartPlay(PWAVEFORMATEX pFormat)
{
	
	AudioOutMute(FALSE);
	writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) &~PLAY_LEFT_CHNNEL &~PLAY_RIGHT_CHNNEL);
	writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) | PLAY_RIGHT_CHNNEL);
	if (pFormat->sChannels != 1)
			writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) | PLAY_LEFT_CHNNEL);

	/* set DMA play destination base address */
	writew(REG_ACTL_PDSTB, _uAuPlayBuffPHYAddr);
	/* set DMA play buffer length */
	writew(REG_ACTL_PDST_LENGTH,_uAuPlayBuffSize);
	/* call back to fill DMA play buffer */
	if (g_fnWAVOutCallBack==NULL)
	    return ERR_NULL_WAVOUTCALLBACK;
	g_fnWAVOutCallBack((UINT8 *)_uAuPlayBuffUncachedAddr, _uAuPlayBuffSize);
	//_tAC97.fnPlayCallBack((UINT8 *)(_uAuPlayBuffAddr + _uAuPlayBuffSize/2), 
		//						_uAuPlayBuffSize/2);
	
	/* start playing */
	_debug_msg("AC97 start playing...\n");
	_bPlayDmaToggle = 0;
	writew(REG_ACTL_ACOS0, 0x1C);
	writew(REG_ACTL_PSR, 0x3);
	writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) | AC_PLAY);
	
	return 0;
}


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      ac97StopPlay                                                     */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Stop AC97 playback immdediately.                                 */
/*                                                                       */
/* INPUTS                                                                */
/*      None    	                                                     */
/*                                                                       */
/* OUTPUTS                                                               */
/*      None                                                             */
/*                                                                       */
/* RETURN                                                                */
/*      0           Success                                              */
/*		Otherwise	error												 */
/*                                                                       */
/*************************************************************************/
VOID  ac97StopPlay()
{
	_debug_msg("AC97 stop playing\n");
    
	/* stop playing */
	writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) & ~AC_PLAY);
	writew(REG_ACTL_ACOS0, 0);
	writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) & ~(PLAY_RIGHT_CHNNEL | PLAY_LEFT_CHNNEL));
	AudioOutMute(TRUE);
	
	return;
}


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      ac97StartRecord                                                  */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Start AC97 record.                                               */
/*                                                                       */
/* INPUTS                                                                */
/*      fnCallBack  client program provided callback function. The audio */
/*                  driver will call back to deliver the newly recorded  */
/*                  block of PCM data                                    */
/*      nSamplingRate  the record sampling rate. Supported sampling      */
/*                  rate are 48000, 44100, 32000, 24000, 22050, 16000,   */
/*                  11025, and 8000 Hz                                   */
/*      nChannels	number of record nChannels                            */
/*					1: single channel, otherwise: double nChannels        */
/*                                                                       */
/* OUTPUTS                                                               */
/*      None                                                             */
/*                                                                       */
/* RETURN                                                                */
/*      0           Success                                              */
/*		Otherwise	error												 */
/*                                                                       */
/*************************************************************************/
static INT  ac97StartRecord(PWAVEFORMATEX pFormat)
{
    if (g_fnWAVInCallBack==NULL)
        return ERR_NULL_WAVINCALLBACK;
 
    AudioInMute(FALSE);
    writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) &~RECORD_LEFT_CHNNEL &~RECORD_RIGHT_CHNNEL);
    writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) | RECORD_RIGHT_CHNNEL);
    if (pFormat->sChannels != 1)
        writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) | RECORD_LEFT_CHNNEL);
	
	/* Install AC97 record interrupt */
#ifdef ECOS
	cyg_interrupt_unmask(IRQ_ACTL);
	cyg_interrupt_enable();
#else	
	//sysSetLocalInterrupt(ENABLE_IRQ);	/* enable CPSR I bit */
	sysEnableInterrupt(IRQ_ACTL);
#endif
	
	//g_fnWAVInCallBack = pFormat->fnWAVInCallBack;

	/* set DMA record destination base address */
	writew(REG_ACTL_RDSTB, _uAuRecBuffPHYAddr);
	
	/* set DMA record buffer length */
	writew(REG_ACTL_RDST_LENGTH, _uAuRecBuffSize);

	/* start recording */
	_debug_msg("AC97 start recording...\n");
	_bRecDmaToggle = 0;
	writew(REG_ACTL_RSR, 0x3);
	writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) | AC_RECORD);
	
	return 0;
}


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      ac97StopRecord                                                  */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Stop AC97 record immediately.                                    */
/*                                                                       */
/* INPUTS                                                                */
/*      None    	                                                     */
/*                                                                       */
/* OUTPUTS                                                               */
/*      None                                                             */
/*                                                                       */
/* RETURN                                                                */
/*      0           Success                                              */
/*		Otherwise	error												 */
/*                                                                       */
/*************************************************************************/
VOID  ac97StopRecord()
{
    _debug_msg("AC97 stop recording\n");
    /* stop recording */
	writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) & ~AC_RECORD);
	
	writew(REG_ACTL_RESET, readw(REG_ACTL_RESET) & ~(RECORD_RIGHT_CHNNEL | RECORD_LEFT_CHNNEL));

	

	
    AudioInMute(TRUE);
	

	return;
}


#endif	/* HAVE_AC97 */

